home *** CD-ROM | disk | FTP | other *** search
/ CD/PC Actual 31 / PC Actual CD 31.iso / dists / SRC / SLIBEXEC.AA / SLIBEXEC / libexec / comsat / comsat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-30  |  8.5 KB  |  320 lines

  1. /*
  2.  * Copyright (c) 1980, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static const char copyright[] =
  36. "@(#) Copyright (c) 1980, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. #if 0
  42. static char sccsid[] = "@(#)comsat.c    8.1 (Berkeley) 6/4/93";
  43. #endif
  44. static const char rcsid[] =
  45.     "$Id: comsat.c,v 1.12 1998/06/30 15:19:48 bde Exp $";
  46. #endif /* not lint */
  47.  
  48. #include <sys/param.h>
  49. #include <sys/socket.h>
  50. #include <sys/stat.h>
  51. #include <sys/file.h>
  52. #include <sys/wait.h>
  53.  
  54. #include <netinet/in.h>
  55.  
  56. #include <ctype.h>
  57. #include <err.h>
  58. #include <errno.h>
  59. #include <netdb.h>
  60. #include <paths.h>
  61. #include <pwd.h>
  62. #include <termios.h>
  63. #include <signal.h>
  64. #include <stdio.h>
  65. #include <stdlib.h>
  66. #include <string.h>
  67. #include <syslog.h>
  68. #include <unistd.h>
  69. #include <utmp.h>
  70.  
  71. int    debug = 0;
  72. #define    dsyslog    if (debug) syslog
  73.  
  74. #define MAXIDLE    120
  75.  
  76. char    hostname[MAXHOSTNAMELEN];
  77. struct    utmp *utmp = NULL;
  78. time_t    lastmsgtime;
  79. int    nutmp, uf;
  80.  
  81. void jkfprintf __P((FILE *, char[], char[], off_t));
  82. void mailfor __P((char *));
  83. void notify __P((struct utmp *, char[], off_t, int));
  84. void onalrm __P((int));
  85. void reapchildren __P((int));
  86.  
  87. int
  88. main(argc, argv)
  89.     int argc;
  90.     char *argv[];
  91. {
  92.     struct sockaddr_in from;
  93.     register int cc;
  94.     int fromlen;
  95.     char msgbuf[256];
  96.  
  97.     /* verify proper invocation */
  98.     fromlen = sizeof(from);
  99.     if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
  100.         err(1, "getsockname");
  101.     openlog("comsat", LOG_PID, LOG_DAEMON);
  102.     if (chdir(_PATH_MAILDIR)) {
  103.         syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
  104.         (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
  105.         exit(1);
  106.     }
  107.     if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
  108.         syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP);
  109.         (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
  110.         exit(1);
  111.     }
  112.     (void)time(&lastmsgtime);
  113.     (void)gethostname(hostname, sizeof(hostname));
  114.     onalrm(0);
  115.     (void)signal(SIGALRM, onalrm);
  116.     (void)signal(SIGTTOU, SIG_IGN);
  117.     (void)signal(SIGCHLD, reapchildren);
  118.     for (;;) {
  119.         cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
  120.         if (cc <= 0) {
  121.             if (errno != EINTR)
  122.                 sleep(1);
  123.             errno = 0;
  124.             continue;
  125.         }
  126.         if (!nutmp)        /* no one has logged in yet */
  127.             continue;
  128.         sigblock(sigmask(SIGALRM));
  129.         msgbuf[cc] = '\0';
  130.         (void)time(&lastmsgtime);
  131.         mailfor(msgbuf);
  132.         sigsetmask(0L);
  133.     }
  134. }
  135.  
  136. void
  137. reapchildren(signo)
  138.     int signo;
  139. {
  140.     while (wait3(NULL, WNOHANG, NULL) > 0);
  141. }
  142.  
  143. void
  144. onalrm(signo)
  145.     int signo;
  146. {
  147.     static u_int utmpsize;        /* last malloced size for utmp */
  148.     static u_int utmpmtime;        /* last modification time for utmp */
  149.     struct stat statbf;
  150.  
  151.     if (time(NULL) - lastmsgtime >= MAXIDLE)
  152.         exit(0);
  153.     (void)alarm((u_int)15);
  154.     (void)fstat(uf, &statbf);
  155.     if (statbf.st_mtime > utmpmtime) {
  156.         utmpmtime = statbf.st_mtime;
  157.         if (statbf.st_size > utmpsize) {
  158.             utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
  159.             if ((utmp = realloc(utmp, utmpsize)) == NULL) {
  160.                 syslog(LOG_ERR, "%s", strerror(errno));
  161.                 exit(1);
  162.             }
  163.         }
  164.         (void)lseek(uf, (off_t)0, L_SET);
  165.         nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp);
  166.     }
  167. }
  168.  
  169. void
  170. mailfor(name)
  171.     char *name;
  172. {
  173.     register struct utmp *utp = &utmp[nutmp];
  174.     register char *cp;
  175.     char *file;
  176.     off_t offset;
  177.     int folder;
  178.     char buf[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1];
  179.     char buf2[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1];
  180.  
  181.     if (!(cp = strchr(name, '@')))
  182.         return;
  183.     *cp = '\0';
  184.     offset = atoi(cp + 1);
  185.     if (!(cp = strchr(cp + 1, ':')))
  186.         file = name;
  187.     else
  188.         file = cp + 1;
  189.     sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utmp[0].ut_name),
  190.         name);
  191.     if (*file != '/') {
  192.         sprintf(buf2, "%s/%.*s", _PATH_MAILDIR,
  193.             (int)sizeof(utmp[0].ut_name), file);
  194.         file = buf2;
  195.     }
  196.     folder = strcmp(buf, file);
  197.     while (--utp >= utmp)
  198.         if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
  199.             notify(utp, file, offset, folder);
  200. }
  201.  
  202. static char *cr;
  203.  
  204. void
  205. notify(utp, file, offset, folder)
  206.     register struct utmp *utp;
  207.     char file[];
  208.     off_t offset;
  209.     int folder;
  210. {
  211.     FILE *tp;
  212.     struct stat stb;
  213.     struct termios tio;
  214.     char tty[20], name[sizeof(utmp[0].ut_name) + 1];
  215.  
  216.     (void)snprintf(tty, sizeof(tty), "%s%.*s",
  217.         _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
  218.     if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) {
  219.         /* A slash is an attempt to break security... */
  220.         syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty);
  221.         return;
  222.     }
  223.     if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
  224.         dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty);
  225.         return;
  226.     }
  227.     dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
  228.     if (fork())
  229.         return;
  230.     (void)signal(SIGALRM, SIG_DFL);
  231.     (void)alarm((u_int)30);
  232.     if ((tp = fopen(tty, "w")) == NULL) {
  233.         dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno));
  234.         _exit(1);
  235.     }
  236.     (void)tcgetattr(fileno(tp), &tio);
  237.     cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ?  "\n" : "\n\r";
  238.     (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name));
  239.     name[sizeof(name) - 1] = '\0';
  240.     (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s",
  241.         cr, name, (int)sizeof(hostname), hostname,
  242.         folder ? cr : "", folder ? "to " : "", folder ? file : "",
  243.         cr, cr);
  244.     jkfprintf(tp, name, file, offset);
  245.     (void)fclose(tp);
  246.     _exit(0);
  247. }
  248.  
  249. void
  250. jkfprintf(tp, user, file, offset)
  251.     register FILE *tp;
  252.     char user[];
  253.     char file[];
  254.     off_t offset;
  255. {
  256.     register unsigned char *cp, ch;
  257.     register FILE *fi;
  258.     register int linecnt, charcnt, inheader;
  259.     register struct passwd *p;
  260.     unsigned char line[BUFSIZ];
  261.  
  262.     /* Set effective uid to user in case mail drop is on nfs */
  263.     if ((p = getpwnam(user)) != NULL)
  264.         (void) setuid(p->pw_uid);
  265.  
  266.     if ((fi = fopen(file, "r")) == NULL)
  267.         return;
  268.  
  269.     (void)fseek(fi, offset, L_SET);
  270.     /*
  271.      * Print the first 7 lines or 560 characters of the new mail
  272.      * (whichever comes first).  Skip header crap other than
  273.      * From, Subject, To, and Date.
  274.      */
  275.     linecnt = 7;
  276.     charcnt = 560;
  277.     inheader = 1;
  278.     while (fgets(line, sizeof(line), fi) != NULL) {
  279.         if (inheader) {
  280.             if (line[0] == '\n') {
  281.                 inheader = 0;
  282.                 continue;
  283.             }
  284.             if (line[0] == ' ' || line[0] == '\t' ||
  285.                 (strncmp(line, "From:", 5) &&
  286.                 strncmp(line, "Subject:", 8)))
  287.                 continue;
  288.         }
  289.         if (linecnt <= 0 || charcnt <= 0) {
  290.             (void)fprintf(tp, "...more...%s", cr);
  291.             (void)fclose(fi);
  292.             return;
  293.         }
  294.         /* strip weird stuff so can't trojan horse stupid terminals */
  295.         for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) {
  296.             /* disable upper controls and enable all other
  297.                8bit codes due to lack of locale knowledge
  298.              */
  299.             if (((ch & 0x80) && ch < 0xA0) ||
  300.                 (!(ch & 0x80) && !isprint(ch) &&
  301.                  !isspace(ch) && ch != '\a' && ch != '\b')
  302.                ) {
  303.                 if (ch & 0x80) {
  304.                     ch &= ~0x80;
  305.                     (void)fputs("M-", tp);
  306.                 }
  307.                 if (iscntrl(ch)) {
  308.                     ch ^= 0x40;
  309.                     (void)fputc('^', tp);
  310.                 }
  311.             }
  312.             (void)fputc(ch, tp);
  313.         }
  314.         (void)fputs(cr, tp);
  315.         --linecnt;
  316.     }
  317.     (void)fprintf(tp, "----%s\n", cr);
  318.     (void)fclose(fi);
  319. }
  320.